//
//  vdShapeContainer.m
//  Void Dead
//
//  Created by Sidney Just on 19.12.09.
//
//  Copyright © 2009 by Sidney Just
//  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 
//  documentation files (the "Software"), to deal in the Software without restriction, including without limitation 
//  the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 
//  and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
//  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 
//  INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 
//  PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE 
//  FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 
//  ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//

#import "vdShapeContainer.h"


@implementation vdShapeContainer
@synthesize shapeCount;

- (void)calculateSize {
	size_x = 0;
	size_y = 0;
	
	for(int i=0; i<shapeCount; i++)
	{
		if(shape[i]->pos_x + shape[i]->size_x > size_x)
			size_x = shape[i]->pos_x + shape[i]->size_x;
		
		if(shape[i]->pos_y + shape[i]->size_y > size_y)
			size_y = shape[i]->pos_y + shape[i]->size_y;
	}
	
	changed = NO;
}

- (int)appendShape {
	shapeCount += 1;
	
	if(shapeCount*12 >= vertexPos)
	{	
		vdLog(@"Resized %@ from <%i> to <%i>", self, vertexPos/12, (vertexPos + 12*appendSize)/12);
		vertexPos += 12*appendSize;
		
		shape = (vdInlineShape **)realloc(shape, vertexPos/12*sizeof(vdInlineShape *));
		
		for(int i=shapeCount; i<vertexPos/12; i++)
		{
			shape[i-1] = (vdInlineShape *)malloc(sizeof(vdInlineShape));
		}
		
		vertices = (GLfloat *)realloc(vertices, (vertexPos)*sizeof(GLfloat));
		texCoords = (GLfloat *)realloc(texCoords, (vertexPos)*sizeof(GLfloat));
	}
	
	
	return shapeCount-1;
}

- (vdInlineShape *)nextShape:(vdInlineShape *)_shp {
	if(shapeCount > 0)
	{
		if(!_shp)
			return shape[0];
		
		for(int i=0; i<shapeCount; i++)
		{
			if(shape[i] == _shp)
			{
				if(i < shapeCount-1)
				{
					return shape[i+1];
				} else {
					return NULL;
				}
			}
		}
	}
	return NULL;
}

- (vdInlineShape *)addShape:(CGPoint)point {
	int i = [self appendShape];
	
	shape[i]->pos_x = point.x;
	shape[i]->pos_y = point.y;
	shape[i]->rotation = 0.0f;
	
	if(texture)
	{
		shape[i]->size_x = texture.dimension_x;
		shape[i]->size_y = texture.dimension_y;
	}
	
	shape[i]->scale_x = 1;
	shape[i]->scale_y = 1;
	
	shape[i]->key = 0;
	
	texCoords[(i*12)+0] = 0;
	texCoords[(i*12)+1] = 1;
	
	texCoords[(i*12)+2] = 1; 
	texCoords[(i*12)+3] = 1;
	
	texCoords[(i*12)+4] = 0; 
	texCoords[(i*12)+5] = 0;
	
	texCoords[(i*12)+8] = 1; 
	texCoords[(i*12)+9] = 0;
	
	texCoords[(i*12)+6] = 1; 
	texCoords[(i*12)+7] = 1;
	
	texCoords[(i*12)+10] = 0; 
	texCoords[(i*12)+11] = 0;
	
	changed = YES;
	return shape[i];
}

- (vdInlineShape *)addShape:(CGPoint)point withKey:(int)key {
	vdInlineShape *temp = [self addShape:point];
	temp->key = key;
	return temp;
}

- (vdInlineShape *)getShapeByKey:(int)key {
	for(int i=0; i<shapeCount; i++)
		if(shape[i]->key == key)
			return shape[i];
	
	return NULL;
}

- (void)removeShape:(vdInlineShape *)aShape {
	for(int i=0; i<shapeCount; i++)
	{
		if(aShape == shape[i])
		{
			free(shape[i]);
			
			for(int j=i; j<shapeCount-1; j++)
			{
				shape[j] = shape[j+1];
				
				for(int g=0; g<12; g++)
				{
					vertices[(j*12)+g] = vertices[((j+1)*12)+g];
					texCoords[(j*12)+g] = texCoords[((j+1)*12)+g];
				}
			}
			
			shapeCount -= 1;
			
			return;
		}
	}
	
	changed = YES;
}

- (void)draw:(NSTimeInterval)deltaTime {
	if(changed)
	{
		[self calculateSize];
	}
	
	if(shapeCount > 0 && texture != NULL)
	{
		int backingHeight = mother.backingHeight;
		int x = 0;
		
		GLfloat *coords = (GLfloat *)malloc((shapeCount*12)*sizeof(GLfloat));
		
		for(int i=0; i<shapeCount; i++)
		{
			if(aPos_x + shape[i]->pos_x + shape[i]->size_x < 0 || aPos_x + shape[i]->pos_x > backingHeight || 
			   aPos_y + shape[i]->pos_y + shape[i]->size_y < 0 || aPos_y + shape[i]->pos_y > backingHeight)
			{
				continue;
			}
			
			if(shape[i]->rotation == 0)
			{
				vertices[x+0] = aPos_x + shape[i]->pos_x;
				vertices[x+1] = backingHeight - aPos_y - shape[i]->pos_y - (shape[i]->size_y * shape[i]->scale_y);
					
				vertices[x+2] = aPos_x + shape[i]->pos_x + (shape[i]->size_x * shape[i]->scale_x);
				vertices[x+3] = backingHeight - aPos_y - shape[i]->pos_y -( shape[i]->size_y * shape[i]->scale_y);
					
				vertices[x+4] = aPos_x + shape[i]->pos_x;
				vertices[x+5] = backingHeight - aPos_y - shape[i]->pos_y;
					
				vertices[x+8] = aPos_x + shape[i]->pos_x + (shape[i]->size_x * shape[i]->scale_x);
				vertices[x+9] = backingHeight - aPos_y - shape[i]->pos_y;
					
				vertices[x+6] = aPos_x + shape[i]->pos_x + (shape[i]->size_x * shape[i]->scale_x);
				vertices[x+7] = backingHeight - aPos_y - shape[i]->pos_y - (shape[i]->size_y * shape[i]->scale_y);
					
				vertices[x+10] = aPos_x + shape[i]->pos_x;
				vertices[x+11] = backingHeight - aPos_y - shape[i]->pos_y;
			} else {
				float vert_temppos_x;
				float vert_temppos_y;
				
				float vert_dist;
				float vert_ang;
				
				float temp = shape[i]->rotation;
				shape[i]->rotation = degreesToRadian(shape[i]->rotation);
				
				vert_temppos_x = (-shape[i]->size_x * shape[i]->scale_x) * 0.5f;
				vert_temppos_y = (-shape[i]->size_y * shape[i]->scale_y) * 0.5f;
				vert_dist = sqrt(vert_temppos_x * vert_temppos_x + vert_temppos_y * vert_temppos_y);
				vert_ang =  atan2(vert_temppos_y, vert_temppos_x);
				vert_temppos_x = cos(vert_ang + shape[i]->rotation) * vert_dist + aPos_x + shape[i]->pos_x + (shape[i]->size_x * shape[i]->scale_x) * 0.5f;
				vert_temppos_y = sin(vert_ang + shape[i]->rotation) * vert_dist + backingHeight - aPos_y - shape[i]->pos_y - (shape[i]->size_y * shape[i]->scale_y) * 0.5f;
				
				vertices[x+0] = vert_temppos_x;
				vertices[x+1] = vert_temppos_y;
				
				vert_temppos_x =  (shape[i]->size_x * shape[i]->scale_x) * 0.5f;
				vert_temppos_y = (-shape[i]->size_y * shape[i]->scale_y) * 0.5f;
				vert_ang = atan2(vert_temppos_y, vert_temppos_x);
				vert_temppos_x = cos(vert_ang + shape[i]->rotation) * vert_dist + aPos_x + shape[i]->pos_x + (shape[i]->size_x * shape[i]->scale_x) * 0.5f;
				vert_temppos_y = sin(vert_ang + shape[i]->rotation) * vert_dist + backingHeight - aPos_y - shape[i]->pos_y - (shape[i]->size_y * shape[i]->scale_y) * 0.5f;
				
				vertices[x+2] = vert_temppos_x;
				vertices[x+3] = vert_temppos_y;
				
				
				vert_temppos_x = (-shape[i]->size_x * shape[i]->scale_x) * 0.5f;
				vert_temppos_y =  (shape[i]->size_y * shape[i]->scale_y) * 0.5f;
				vert_ang = atan2(vert_temppos_y, vert_temppos_x);
				vert_temppos_x = cos(vert_ang + shape[i]->rotation) * vert_dist + aPos_x + shape[i]->pos_x + (shape[i]->size_x * shape[i]->scale_x) * 0.5f;
				vert_temppos_y = sin(vert_ang + shape[i]->rotation) * vert_dist + backingHeight - aPos_y - shape[i]->pos_y - (shape[i]->size_y * shape[i]->scale_y) * 0.5f;
				
				vertices[x+4] = vert_temppos_x;
				vertices[x+5] = vert_temppos_y;
				
				
				vert_temppos_x = (shape[i]->size_x * shape[i]->scale_x) * 0.5f;
				vert_temppos_y = (shape[i]->size_y * shape[i]->scale_y) * 0.5f;
				vert_ang = atan2(vert_temppos_y, vert_temppos_x);
				vert_temppos_x = cos(vert_ang + shape[i]->rotation) * vert_dist + aPos_x + shape[i]->pos_x + (shape[i]->size_x * shape[i]->scale_x) * 0.5f;
				vert_temppos_y = sin(vert_ang + shape[i]->rotation) * vert_dist + backingHeight - aPos_y - shape[i]->pos_y - (shape[i]->size_y * shape[i]->scale_y) * 0.5f;
				
				vertices[x+8] = vert_temppos_x;
				vertices[x+9] = vert_temppos_y;
				
				
				vert_temppos_x =  (shape[i]->size_x * shape[i]->scale_x) * 0.5f;
				vert_temppos_y = (-shape[i]->size_y * shape[i]->scale_y) * 0.5f;
				vert_ang = atan2(vert_temppos_y, vert_temppos_x);
				vert_temppos_x = cos(vert_ang + shape[i]->rotation) * vert_dist + aPos_x + shape[i]->pos_x + (shape[i]->size_x * shape[i]->scale_x) * 0.5f;
				vert_temppos_y = sin(vert_ang + shape[i]->rotation) * vert_dist + backingHeight - aPos_y - shape[i]->pos_y - (shape[i]->size_y * shape[i]->scale_y) * 0.5f;
				
				vertices[x+6] = vert_temppos_x;
				vertices[x+7] = vert_temppos_y;
				
				
				vert_temppos_x = (-shape[i]->size_x * shape[i]->scale_x) * 0.5f;
				vert_temppos_y =  (shape[i]->size_y * shape[i]->scale_y) * 0.5f;
				vert_ang = atan2(vert_temppos_y, vert_temppos_x);
				vert_temppos_x = cos(vert_ang + shape[i]->rotation) * vert_dist + aPos_x + shape[i]->pos_x + (shape[i]->size_x * shape[i]->scale_x) * 0.5f;
				vert_temppos_y = sin(vert_ang + shape[i]->rotation) * vert_dist + backingHeight - aPos_y - shape[i]->pos_y - (shape[i]->size_y * shape[i]->scale_y) * 0.5f;
				
				vertices[x+10] = vert_temppos_x;
				vertices[x+11] = vert_temppos_y; 
				
				shape[i]->rotation = temp;
			}

			
			coords[x+0] = texCoords[(i*12)+0];
			coords[x+1] = texCoords[(i*12)+1];
			
			coords[x+2] = texCoords[(i*12)+2]; 
			coords[x+3] = texCoords[(i*12)+3];
			
			coords[x+4] = texCoords[(i*12)+4]; 
			coords[x+5] = texCoords[(i*12)+5];
			
			coords[x+6] = texCoords[(i*12)+6]; 
			coords[x+7] = texCoords[(i*12)+7];
			
			coords[x+8] = texCoords[(i*12)+8]; 
			coords[x+9] = texCoords[(i*12)+9];
			
			coords[x+10] = texCoords[(i*12)+10]; 
			coords[x+11] = texCoords[(i*12)+11];
			
			x += 12;
		}

		[[vdRenderer sharedRenderer] setMode:GL_TRIANGLES];
		[[vdRenderer sharedRenderer] addVertices:vertices texCoords:coords posPerVertex:2 size:x texture:texture color:color];
		
		free(coords);
	}
}

- (void)setTexture:(vdTexNode *)tex {
	texture = tex;
	
	if(texture)
	{
		for(int i=0; i<shapeCount; i++)
		{
			shape[i]->size_x = texture.dimension_x;
			shape[i]->size_y = texture.dimension_y;
		}
	}
}

- (void)setAppendSize:(int)_size {
	if(_size > 0)
	{
		appendSize = _size;
	} else {
		vdLog(@"Append size must be greater than 0!");
	}

}

- (id)init {
	if(self = [super init])
	{
		vertexPos = 0;
		shapeCount = 0;
		appendSize = 100;
		shape = (vdInlineShape **)malloc(sizeof(vdInlineShape *));
		
		vertices = (GLfloat *)malloc(sizeof(GLfloat));
		texCoords = (GLfloat *)malloc(sizeof(GLfloat));
		
		texture = NULL;
		
		changed = NO;
	}
	return self;
}

- (void)dealloc {
	for(int i=0; i<(vertexPos/12)-1; i++)
	{
		free(shape[i]);	
	}
	
	free(shape);
	free(vertices);
	free(texCoords);
	
	[super dealloc];
}

@end
